package com.marketing.auth.service.impl;

import com.marketing.auth.dto.UserInfoDto;
import com.marketing.auth.entity.User;
import com.marketing.auth.service.TokenService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Token管理服务实现类
 */
@Service
public class TokenServiceImpl implements TokenService {

    private static final Logger logger = LoggerFactory.getLogger(TokenServiceImpl.class);

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // Redis Key前缀
    private static final String TOKEN_PREFIX = "auth:token:";
    private static final String USER_TOKEN_PREFIX = "auth:user_tokens:";

    @Override
    public void storeToken(String token, UserInfoDto userInfo, Long expireTime) {
        logger.info("开始存储Token到Redis，用户ID: {}, 用户名: {}, 过期时间: {}秒", userInfo.getId(), userInfo.getUsername(), expireTime);
        
        try {
            String tokenKey = TOKEN_PREFIX + token;
            String userTokenKey = USER_TOKEN_PREFIX + userInfo.getId();
            
            logger.debug("Redis Key信息 - tokenKey: {}, userTokenKey: {}", tokenKey, userTokenKey);
            
            // 存储Token对应的用户信息
            redisTemplate.opsForValue().set(tokenKey, userInfo, expireTime, TimeUnit.SECONDS);
            logger.debug("用户信息存储成功， tokenKey: {}", tokenKey);
            
            // 将Token添加到用户的Token集合中（用于管理用户的多个Token）
            redisTemplate.opsForSet().add(userTokenKey, token);
            redisTemplate.expire(userTokenKey, expireTime, TimeUnit.SECONDS);
            logger.debug("用户Token集合更新成功， userTokenKey: {}", userTokenKey);
            
            logger.info("Token存储到Redis成功，用户: {}, 用户ID: {}", userInfo.getUsername(), userInfo.getId());
        } catch (Exception e) {
            logger.error("存储Token到Redis失败，用户ID: {}, 用户名: {}, 异常: {}", userInfo.getId(), userInfo.getUsername(), e.getMessage(), e);
            throw new RuntimeException("存储Token失败", e);
        }
    }

    @Override
    public boolean isTokenValid(String token) {
        logger.debug("检查Token在Redis中的有效性");
        
        try {
            String tokenKey = TOKEN_PREFIX + token;
            boolean exists = Boolean.TRUE.equals(redisTemplate.hasKey(tokenKey));
            
            if (exists) {
                logger.debug("Token在Redis中存在且有效");
            } else {
                logger.debug("Token在Redis中不存在或已过期");
            }
            
            return exists;
        } catch (Exception e) {
            logger.error("检查Token有效性时发生异常: {}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public UserInfoDto getUserByToken(String token) {
        logger.debug("从Redis获取Token对应的用户信息");
        
        try {
            String tokenKey = TOKEN_PREFIX + token;
            Object userObj = redisTemplate.opsForValue().get(tokenKey);
            
            if (userObj instanceof UserInfoDto) {
                UserInfoDto userInfo = (UserInfoDto) userObj;
                logger.debug("从Redis获取用户信息成功，用户ID: {}, 用户名: {}", userInfo.getId(), userInfo.getUsername());
                return userInfo;
            } else {
                logger.warn("从Redis获取的用户信息类型不正确或为空，类型: {}", userObj != null ? userObj.getClass().getSimpleName() : "null");
                return null;
            }
        } catch (Exception e) {
            logger.error("从Redis获取用户信息时发生异常: {}", e.getMessage(), e);
            return null;
        }
    }

    @Override
    public boolean refreshToken(String token, Long expireTime) {
        logger.debug("开始刷新Token过期时间，新过期时间: {}秒", expireTime);
        
        try {
            String tokenKey = TOKEN_PREFIX + token;
            
            if (Boolean.TRUE.equals(redisTemplate.hasKey(tokenKey))) {
                // 续期Token
                redisTemplate.expire(tokenKey, expireTime, TimeUnit.SECONDS);
                logger.debug("Token过期时间续期成功，tokenKey: {}", tokenKey);
                
                // 获取用户信息并续期用户Token集合
                UserInfoDto userInfo = getUserByToken(token);
                if (userInfo != null) {
                    String userTokenKey = USER_TOKEN_PREFIX + userInfo.getId();
                    redisTemplate.expire(userTokenKey, expireTime, TimeUnit.SECONDS);
                    logger.debug("用户Token集合过期时间续期成功，userTokenKey: {}", userTokenKey);
                    logger.info("Token续期成功，用户: {}, 续期时间: {}秒", userInfo.getUsername(), expireTime);
                } else {
                    logger.warn("Token续期时无法获取用户信息");
                }
                return true;
            } else {
                logger.warn("Token续期失败：Token在Redis中不存在");
                return false;
            }
        } catch (Exception e) {
            logger.error("Token续期过程中发生异常: {}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public void removeToken(String token) {
        logger.info("开始从Redis删除Token");
        
        try {
            String tokenKey = TOKEN_PREFIX + token;
            
            // 获取用户信息
            UserInfoDto userInfo = getUserByToken(token);
            String username = userInfo != null ? userInfo.getUsername() : "unknown";
            Long userId = userInfo != null ? userInfo.getId() : null;
            
            // 删除Token
            Boolean deleted = redisTemplate.delete(tokenKey);
            logger.debug("Token删除结果，tokenKey: {}, 删除成功: {}", tokenKey, deleted);
            
            // 从用户Token集合中移除
            if (userInfo != null) {
                String userTokenKey = USER_TOKEN_PREFIX + userInfo.getId();
                Long removedCount = redisTemplate.opsForSet().remove(userTokenKey, token);
                logger.debug("从用户Token集合中移除，userTokenKey: {}, 移除数量: {}", userTokenKey, removedCount);
            }
            
            logger.info("Token删除成功，用户: {}, 用户ID: {}", username, userId);
        } catch (Exception e) {
            logger.error("删除Token过程中发生异常: {}", e.getMessage(), e);
        }
    }

    @Override
    public void removeUserAllTokens(Long userId) {
        logger.info("开始删除用户所有Token，用户ID: {}", userId);
        
        try {
            String userTokenKey = USER_TOKEN_PREFIX + userId;
            
            // 获取用户所有Token
            Set<Object> tokens = redisTemplate.opsForSet().members(userTokenKey);
            
            if (tokens != null && !tokens.isEmpty()) {
                logger.debug("发现用户有 {} 个Token需要删除，用户ID: {}", tokens.size(), userId);
                
                // 删除所有Token
                int deletedCount = 0;
                for (Object token : tokens) {
                    String tokenKey = TOKEN_PREFIX + token;
                    Boolean deleted = redisTemplate.delete(tokenKey);
                    if (Boolean.TRUE.equals(deleted)) {
                        deletedCount++;
                    }
                    logger.debug("删除Token: {}, 结果: {}", tokenKey, deleted);
                }
                
                logger.debug("成功删除 {}/{} 个Token，用户ID: {}", deletedCount, tokens.size(), userId);
            } else {
                logger.debug("用户没有活跃的Token，用户ID: {}", userId);
            }
            
            // 删除用户Token集合
            Boolean deletedSet = redisTemplate.delete(userTokenKey);
            logger.debug("删除用户Token集合，userTokenKey: {}, 结果: {}", userTokenKey, deletedSet);
            
            logger.info("用户所有Token删除成功，用户ID: {}", userId);
        } catch (Exception e) {
            logger.error("删除用户所有Token过程中发生异常，用户ID: {}, 异常: {}", userId, e.getMessage(), e);
        }
    }

    /**
     * 获取Token的剩余过期时间
     * @param token JWT Token
     * @return 剩余时间（秒），-1表示永不过期，-2表示不存在
     */
    public Long getTokenExpireTime(String token) {
        String tokenKey = TOKEN_PREFIX + token;
        return redisTemplate.getExpire(tokenKey, TimeUnit.SECONDS);
    }

    /**
     * 检查用户是否有活跃的Token
     * @param userId 用户ID
     * @return 是否有活跃Token
     */
    public boolean hasActiveTokens(Long userId) {
        String userTokenKey = USER_TOKEN_PREFIX + userId;
        Long tokenCount = redisTemplate.opsForSet().size(userTokenKey);
        return tokenCount != null && tokenCount > 0;
    }
}